package com.foss.component;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import com.foss.base.BslApplication;
import com.foss.base.BslConfig;
import com.foss.utils.AesTool;
import com.foss.utils.AppLog;

import java.io.*;

/**
 * description: 自定义的ContentProvider，用于处理WebView的资源加载请求,并根据url进行鉴别处理。
 *
 * @date: 2014年5月8日
 * @author: wzq
 */
public class ProviderCrypt extends ContentProvider {
    private static final String TAG = ProviderCrypt.class.getSimpleName();

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) {

        ParcelFileDescriptor parcel = null;
        try {
            InputStream inputStream = getInputStream(uri);
            if (inputStream != null) {
                InputStream resultStream = AesTool.getInstance().decryptStream(inputStream);
                // check result
                if (resultStream != null) {
                    parcel = ParcelFileDescriptorUtil.pipeFrom(resultStream);
                }
            }
        } catch (FileNotFoundException e) {
            AppLog.e("file not found : uri=" + uri);
        } catch (IOException e) {
            AppLog.e("Stream to ParcelFileDescriptor error " + e.toString());
        }
        if (parcel == null) {
            AppLog.e("null result at:" + uri);
        }
        return parcel;
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        throw new UnsupportedOperationException("Not supported by this provider");
    }

    @Override
    public String getType(Uri uri) {
        throw new UnsupportedOperationException("Not supported by this provider");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        throw new UnsupportedOperationException("Not supported by this provider");
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("Not supported by this provider");
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("Not supported by this provider");
    }

    private static InputStream getInputStream(Uri uri) {
        AppLog.v("fetching:uri = " + uri);

        final String uriPath = uri.getPath();
        AppLog.v("uriPath = " + uriPath);

        // 首先根据 关键字段进行判定
        if (uriPath.contains(BslConfig.ASSETS_FOLDER_AFTER_SCHEME)) {
            return streamFromAsset(uriPath);
        }
        if (uriPath.contains(BslConfig.APP_FOLDER_IN_SD)) {
            return streamFromSdFile(uriPath);
        }

        AppLog.e("危险 : uri中不含有关键字段，必须根据 BslConfig.IS_SANDBOX 进行判断");
        if (BslConfig.IS_SANDBOX) {
            return streamFromSdFile(uriPath);
        } else {
            return streamFromAsset(uriPath);
        }
    }

    /**
     * 根据provider scheme后面到路径，找到相应 sd卡 目录下到文件流
     *
     * @param pathAfterScheme provider scheme后面到路径
     * @return 文件流
     */
    private static InputStream streamFromSdFile(String pathAfterScheme) {
        AppLog.i("read sd");
        String absPath = pathAfterScheme;
        if (!pathAfterScheme.startsWith(BslConfig.WWW_FOLDER_IN_SD)) {
            if (pathAfterScheme.startsWith("/")) {
                absPath = BslConfig.WWW_FOLDER_IN_SD + pathAfterScheme;
            } else {
                absPath = BslConfig.WWW_FOLDER_IN_SD + "/" + pathAfterScheme;
            }
        }
        AppLog.i("absPath = " + absPath);
        File f = new File(absPath);
        try {
            return new FileInputStream(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据provider scheme后面到路径，找到相应 assets 目录下到文件流
     *
     * @param pathAfterScheme provider scheme后面到路径
     * @return 文件流
     */
    private static InputStream streamFromAsset(String pathAfterScheme) {
        // asset读取
        AppLog.i("read asset");
        if (pathAfterScheme.startsWith(BslConfig.ASSETS_FOLDER_AFTER_SCHEME)) {
            String assetPath = pathAfterScheme.substring(BslConfig.ASSETS_FOLDER_AFTER_SCHEME.length(), pathAfterScheme.length());
            if (!assetPath.startsWith("www/")) {
                assetPath = "www/" + assetPath;
            }
            AppLog.i("assetPath = " + assetPath);
            AssetManager assetManager = BslApplication.getInstance().getAssets();
            try {
                return assetManager.open(assetPath);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            AppLog.e("unknown path = " + pathAfterScheme);
        }
        return null;
    }


//    /**
//     * 获取文件完整路径，如果不是以sd开头，说明是相对根目录的路径
//     *
//     * @return 完整路径 /mnt/sdcard/.../www/.../myfile.xx
//     */
//    private static String getFullPath(String filePath) {
//        String path = filePath;
//        if (!filePath.startsWith(BslConfig.WWW_FOLDER_IN_SD)) {
//            if (filePath.startsWith("/")) {
//                path = BslConfig.WWW_FOLDER_IN_SD + filePath;
//            } else {
//                path = BslConfig.WWW_FOLDER_IN_SD + "/" + filePath;
//            }
//        }
//        return path;
//    }

    static class ParcelFileDescriptorUtil {
        public static ParcelFileDescriptor pipeFrom(InputStream inputStream) throws IOException {
            ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
            ParcelFileDescriptor readSide = pipe[0];
            ParcelFileDescriptor writeSide = pipe[1];
            // start the transfer thread
            new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide)).start();
            return readSide;
        }

        static class TransferThread extends Thread {
            final InputStream mIn;
            final OutputStream mOut;

            TransferThread(InputStream in, OutputStream out) {
                super("ParcelFileDescriptor Transfer Thread");
                mIn = in;
                mOut = out;
                setDaemon(true);
            }

            @Override
            public void run() {
                byte[] buf = new byte[1024];
                try {
                    int len;
                    while ((len = mIn.read(buf)) > 0) {
                        mOut.write(buf, 0, len);
                    }
                    mOut.flush(); // just to be safe
                } catch (IOException e) {
                    AppLog.e("TransferThread " + e.toString());
                } finally {
                    try {
                        mIn.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        mOut.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}
